﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Media3D;
using System.Windows.Media;
using System.Windows;
using System.Diagnostics;

namespace Eniux.Windows.ThreeDEngine.Helper
{
    /// <summary>
    /// 几何模型点生成器
    /// </summary>
    public class PointGeometryBuilder : ScreenGeometryBuilder
    {
        #region 构造

        /// <summary>
        /// 默认构造
        /// </summary>
        /// <param name="visual"></param>
        public PointGeometryBuilder(Visual3D visual)
            : base(visual)
        {
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 创建索引
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        public Int32Collection CreateIndices(int n)
        {
            var indices = new Int32Collection(n * 6);

            for (int i = 0; i < n; i++)
            {
                indices.Add(i * 4 + 2);
                indices.Add(i * 4 + 1);
                indices.Add(i * 4 + 0);

                indices.Add(i * 4 + 2);
                indices.Add(i * 4 + 3);
                indices.Add(i * 4 + 1);
            }

            indices.Freeze();
            return indices;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="points"></param>
        /// <param name="size"></param>
        /// <param name="depthOffset"></param>
        /// <returns></returns>
        public Point3DCollection CreatePositions(IList<Point3D> points, double size = 1.0, double depthOffset = 0.0)
        {
            double halfSize = size / 2.0;
            int numPoints = points.Count;

            var outline = new[]
                {
                    new Vector(-halfSize, halfSize), new Vector(-halfSize, -halfSize), new Vector(halfSize, halfSize), 
                    new Vector(halfSize, -halfSize)
                };

            var positions = new Point3DCollection(numPoints * 4);

            for (int i = 0; i < numPoints; i++)
            {
                var screenPoint = (Point4D)points[i] * this.visualToScreen;
                foreach (var v in outline)
                {
                    var p = screenPoint;
                    p.X += v.X * p.W;
                    p.Y += v.Y * p.W;
                    if (depthOffset != 0)
                    {
                        p.Z -= depthOffset * p.W;
                        p *= this.screenToVisual;
                        positions.Add(new Point3D(p.X / p.W, p.Y / p.W, p.Z / p.W));
                    }
                    else
                    {
                        p *= this.screenToVisual;
                        Debug.Assert(Math.Abs(p.W - 1) < 1e-6, "Something wrong with the homogeneous coordinates.");
                        positions.Add(new Point3D(p.X, p.Y, p.Z));
                    }
                }
            }

            positions.Freeze();
            return positions;
        }

        #endregion
    }
}
